import inspect
DEAULT_VALUE="ANY"
import sys

sys.path.append("./")
from rule import *
class Http(object):
	SIP=DEAULT_VALUE
	DIP=DEAULT_VALUE
	SPORT=DEAULT_VALUE
	DPORT=DEAULT_VALUE
	URI=DEAULT_VALUE
	METHOD=DEAULT_VALUE
	TIME=DEAULT_VALUE
	USER=DEAULT_VALUE
"""
general classes
"""
class exceptions(Exception):
		class InvaildArgsLen(Exception):
				args="Error:InvaildArgsLen"

op=["=","!=","<",">","<=",">=","in","!in"]

class Effect(object):
	ALLOW=1
	DENY=0


		
class Policy(object):
	GROUP=DEAULT_VALUE
	TIME=DEAULT_VALUE
	OWNER=DEAULT_VALUE
	def __init__(self):
		self.rules=[]
		pass

	def add(self,rule):
		self.rules.append(rule)
		pass

	def submit(self):
		res=[]
		for i in self.rules:
			res.append(str(i))

class Rule(object):
	GROUP=DEAULT_VALUE
	TIME=DEAULT_VALUE
	OWNER=DEAULT_VALUE
	PRINCIPLE=DEAULT_VALUE
	ACTION=DEAULT_VALUE
	EFFECT=Effect.DENY
	TARGET=DEAULT_VALUE
	CONDITION={}

	def add(self,attr,*args):
		t=inspect.stack()[-2][-2][0]
		attr=t[t.find("(")+1:t.find(")")]
		attr=attr.split(",")[0].split(".")[1]
		op=args[0]
		value=args[1]
		if Rule.PRINCIPLE==DEAULT_VALUE:
			Rule.PRINCIPLE=[]
			Rule.PRINCIPLE.append(attr)
		else:
			Rule.PRINCIPLE.append(attr)
		Rule.PRINCIPLE=list(set(Rule.PRINCIPLE))
		Rule.CONDITION[attr]=(op,value)

	def __str__(self):
		members = [attr for attr in dir(Rule()) if not callable(attr) and not attr.startswith("__") and attr!="add"]
		res={}
		for m in members:
			res[m]=getattr(self,m)
		return str(res)


attr_checker=Attribute()
#print a.attr_info
tree_order={}
key_order=sorted(attr_checker.attr_info.keys())
for ct_key in attr_checker.attr_info:
	tree_order[ct_key]=sorted(attr_checker.attr_info[ct_key].keys(),reverse=True)
#print tree_order
#print key_order
class Node(object):
	"""docstring for Node"""
	def __init__(self, value):
		self.value = value
		self.child={}
	def set_child(self,n):
		self.child[n.value]=n

		
def build_tree(p,ct="Subject"):
	attr=p[ct]
	#print attr
	tree={}
	root_node=Node("root")
	cur_node=root_node
	for k in tree_order[ct]:
		n=Node(k)
		cur_node.set_child(n)
		cur_node=n
	print root_node.child['user_name'].child.keys()


class Auth(object):
	"""docstring for Auth"""
	def __init__(self):
		super(Auth, self).__init__()
		self.auth_db=self.init_auth()

	def init_auth(self):
		auth={}
		auth["admin:admin"]={"url":"$HOST/v1/AUTH_admin","key":"admin"}
		auth["test:test1"]={"url":"$HOST/v1/AUTH_test","key":"test1"}
		auth["test:test2"]={"url":"$HOST/v1/AUTH_test","key":"test2"}
		auth["test2:tester"]={"url":"$HOST/v1/AUTH_test2","key":"tester"}
		return auth

	def auth(self,a,u,k):
		uid=a+":"+u
		if uid in self.auth_db:
			if self.auth_db[uid]["key"]==k:
				return True
		return False

	def add_user(self,a,u,k,url):
		uid=a+":"+u
		self.auth_db[uid]={"url":url,"key":key}

	def del_user(self,a,u):
		uid=a+":"+u
		self.auth_db.pop(uid)



class PolicyEngine(object):
	"""docstring for PolicyEngine"""
	def __init__(self):
		self.policy_store=[]
		self.op=Operation()
		self.ac=Attribute()
		self.st_table={}
		self.cache={}
		pass

	def parse_policy(self,p):
		for tp in p:
			self.policy_store.append(tp)
		pass

	def save_state(self,meta):
		import hashlib
		#h=str(meta)
		h=hashlib.sha224(str(meta)).hexdigest()
		if h in self.st_table:
			ct=time.time()
			st=self.st_table[h]['s_time']
			cn=self.st_table[h]['count']
			self.st_table[h]['count']=cn+1
			self.st_table[h]['rate']=cn/(ct-st)
			self.st_table[h]['c_time']=ct
		else:
			self.st_table[h]={}
			self.st_table[h]['count']=1
			self.st_table[h]['c_time']=time.time()
			self.st_table[h]['s_time']=time.time()
			self.st_table[h]['rate']=1
		return h

	def do_action(self,r,meta):
		gr=r[0]
		ar=r[1]
		print r
		if gr!=None:
			if gr=="META":
				print "call logger"
		if ar==None:
			print "call controller"
		return ar

	def lookup(self,meta):
		r1=r2=None
		h=self.save_state(meta)

		for tp in self.policy_store:
			if tp['Global']:
				res=self.lookup_one(tp,h,meta,1)
				if res:
					if not tp["Condition"]:
						r1=tp['Decision']
						break
					else:
						if not self.lookup_cond(tp,h):
							r1="DENY"
						else:
							r1=tp['Decision']
							break
				if res==False:
					r1="DENY"
					break
						
		for tp in self.policy_store:
			if not tp['Global']:
				res=self.lookup_one(tp,h,meta,0)
				if res:
					if not tp["Condition"]:
						r2=tp['Decision']
						break
					else:
						if not self.lookup_cond(tp,h):
							r2="DENY"
						else:
							r2=tp['Decision']
							break
				if res==False:
					r2="DENY"
					break

		return self.do_action((r1,r2),meta)
		
	def lookup_one(self,p,h,meta,gl):
		pid=p["id"]
		if (h,gl,pid) in self.cache:
			return self.cache[(h,gl,pid)]
		action=meta[2]['action'].lower()
		all_match=True
		targets=['Subject','Resource']
		for kw in (0,1) :
			tp=p[targets[kw]]
			if not tp:
				continue
			for k in tp:
				if k in meta[kw]:
					v=str(meta[kw][k])

					for r in tp[k]:
						op=r["op"]
						tv=r["value"]
						#print v,op,tv
						c=self.ac.attr_info[targets[kw]][k]
						if not self.op.compare(v,op,tv,c):
							self.cache[(h,gl,pid)]=False
							return False
				else:
					all_match=False
			"""
			if not tp:
				continue
			for k in meta[kw]:
				v=str(meta[kw][k])
				if k in tp:
					#match one field
					for r in tp[k]:
						op=r["op"]
						tv=r["value"]
						c=self.ac.attr_info[targets[kw]][k]
						if not self.op.compare(v,op,tv,c):
							self.cache[(h,gl,pid)]=False
							return False
				else:
					all_match=False
			"""
		
		if not action in p['Action']:
			self.cache[(h,gl,pid)]=False
			return False
		if all_match:
			self.cache[(h,gl,pid)]=True
			return True
		self.cache[(h,gl,pid)]=None
		return None

	def lookup_cond(self,p,h):
		tp=p['Condition']
		for k in tp:
			for r in tp[k]:
				tv=float(r['value'])
				op=r['op']
				if k=="interval":
					if not self.st_table[h][count]%tv==0:
						return False
				else:
					v=float(self.st_table[h][k])
					if not self.op.compare(v,op,tv,k):
						return False
		return True

if __name__ == '__main__':
	import cPickle
	from random import randrange
	p=cPickle.load(open("test.po"))
	PE=PolicyEngine()
	PE.parse_policy(p)
	for i in range(0,15):
		port=randrange(80,83)
		action=["put","get","head"][randrange(80)%3]
		port=80
		action="put"
		meta=[{"ip":"127.0.0.2","port":"80","act":"aaa"},{"create_time":"1325397700"},{"action":action}]
		#print port,action
		r=PE.lookup(meta)
		print r
	meta=[{"ip":"127.0.0.2","port":"0","aa":"aa"},{},{"action":"put"}]
	print PE.lookup(meta)
	meta=[{"tip":"127.0.0.2","port":"80","act":"aaa"},{"create_time":"1325397700"},{"action":action}]
	print PE.lookup(meta)



		

